package loveqq.niceexcel.converter;

import cn.hutool.core.util.ReflectUtil;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import loveqq.niceexcel.converter.internal.AutoConverter;
import org.apache.poi.ss.usermodel.CellType;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static loveqq.niceexcel.constant.DefaultConsts.DEFAULT_CONVERTER_CLASSES;
import static org.apache.poi.ss.usermodel.CellType.*;

/**
 * @author zhongjh@tsintergy.com
 * @date 2022-08-18
 */
public class ConverterCache {
    /**
     * 内置转换器缓存
     */
    private static final Map<ConverterKey, Converter> DEFAULT_CONVERTER_CACHE;
    /**
     * 转换器缓存
     */
    private final Map<ConverterKey, Converter> cache = new HashMap<>(DEFAULT_CONVERTER_CACHE);

    static {
        Map<ConverterKey, Converter> converterMap = new HashMap<>();
        for (Class<? extends Converter> converterClass : DEFAULT_CONVERTER_CLASSES) {
            Converter<?> converter = ReflectUtil.newInstance(converterClass);
            ConverterKey key = new ConverterKey(converter.supportJavaType(), converter.supportExcelType());
            converterMap.put(key, converter);
        }
        DEFAULT_CONVERTER_CACHE = Collections.unmodifiableMap(converterMap);
    }

    /**
     * 获取转换器
     *
     * @param javaType Java数据类型
     * @param cellType Excel单元格类型
     * @return 转换器
     */
    public Converter<?> get(Class<?> javaType, CellType cellType) {
        return cache.get(new ConverterKey(javaType, cellType));
    }

    /**
     * 缓存转换器
     *
     * @param converter 转换器对象
     */
    public void put(Converter<?> converter) {
        cache.put(new ConverterKey(converter.supportJavaType(), converter.supportExcelType()), converter);
    }

    /**
     * 缓存转换器
     *
     * @param javaType      Java数据类型
     * @param cellType      Excel单元格类型
     * @param converterType 转换器类(保证公共构造器)
     */
    public void put(Class<?> javaType, CellType cellType, Class<Converter<?>> converterType) {
        if (AutoConverter.class.equals(converterType)) {
            String message = String.format("不支持AutoConverter: javaType=[%s], cellType=[%s]", javaType.getName(), cellType);
            throw new UnsupportedOperationException(message);
        }
        put(ReflectUtil.newInstance(converterType));
    }

    @Getter
    @EqualsAndHashCode
    private static final class ConverterKey {
        private final Class<?> javaType;
        private final CellType cellType;

        public ConverterKey(Class<?> javaType, CellType cellType) {
            this.javaType = javaType;
            this.cellType = (null == cellType || NUMERIC == cellType || BOOLEAN == cellType || FORMULA == cellType) ? cellType : STRING;
        }
    }

}
